/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.yzbdl.lanius.orchestrate.serv.service.system.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yzbdl.lanius.orchestrate.common.base.entity.IdFieldEntity;
import org.yzbdl.lanius.orchestrate.common.dto.system.*;
import org.yzbdl.lanius.orchestrate.common.entity.system.UserEntity;
import org.yzbdl.lanius.orchestrate.common.entity.system.UserOrgEntity;
import org.yzbdl.lanius.orchestrate.common.entity.system.UserRoleEntity;
import org.yzbdl.lanius.orchestrate.common.enums.UserStatusEnum;
import org.yzbdl.lanius.orchestrate.common.exception.runtime.BusinessException;
import org.yzbdl.lanius.orchestrate.common.utils.AesUtils;
import org.yzbdl.lanius.orchestrate.common.utils.BcryptEncoderUtil;
import org.yzbdl.lanius.orchestrate.common.utils.SpecialCharacterUtil;
import org.yzbdl.lanius.orchestrate.common.vo.system.AccountVO;
import org.yzbdl.lanius.orchestrate.common.vo.system.NickNameVo;
import org.yzbdl.lanius.orchestrate.common.vo.system.UserVo;
import org.yzbdl.lanius.orchestrate.serv.mapper.system.OrgMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.system.UserMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.system.UserOrgMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.system.UserRoleMapper;
import org.yzbdl.lanius.orchestrate.serv.service.system.UserOrgService;
import org.yzbdl.lanius.orchestrate.serv.service.system.UserService;
import org.yzbdl.lanius.orchestrate.serv.utils.CurrentUserUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用户服务实现
 *
 * @author chenjunhao@yzbdl.ac.cn
 * @date 2022-04-07 14:14
 */
@Slf4j
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    @Value("${encryption.user-key}")
    String encryptKey;

    @Autowired
    UserOrgMapper userOrgMapper;

    @Autowired
    UserOrgService orgService;

    @Autowired
    UserRoleMapper userRoleMapper;

    @Autowired
    OrgMapper orgMapper;

    /**
     * 用户列表
     * @param userListDto 用户查询条件
     * @param page 分页内容
     * @return 用户分页列表
     */
    @Override
    public Page<UserVo> listUserPage(UserListDTO userListDto, Page<UserVo> page) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new QueryWrapper<UserEntity>().lambda()
                .eq(UserEntity::getDeleted, false)
                .like(StringUtils.isNotEmpty(userListDto.getNickName()), UserEntity::getNickName, SpecialCharacterUtil.escapeStr(userListDto.getNickName()))
                .like(StringUtils.isNotEmpty(userListDto.getUserName()), UserEntity::getUsername, SpecialCharacterUtil.escapeStr(userListDto.getUserName()));
        List<UserVo> userVos = this.baseMapper.queryUserVoByOrgId(
                CurrentUserUtil.getCurrentUserOrgId(),
                (page.getCurrent() - 1) * page.getSize(),
                page.getSize(),
                queryWrapper);
        page.setTotal(this.baseMapper.selectCount(queryWrapper));
        page.setRecords(userVos);
        page.setTotal(this.baseMapper.countUserVoByOrgId(CurrentUserUtil.getCurrentUserOrgId(), queryWrapper));
        return page;
    }

    /**
     * 管理员用户列表
     *
     * @param userListDto 用户查询条件
     * @param page        分页内容
     * @return 用户分页列表
     */
    @Override
    public Page<AccountVO> listAccountPage(UserListDTO userListDto, Page<AccountVO> page) {
        LambdaQueryWrapper<UserEntity> queryWrapper =
                new QueryWrapper<UserEntity>().lambda()
                        .eq(UserEntity::getDeleted, false)
                        .like(StringUtils.isNotEmpty(userListDto.getNickName()), UserEntity::getNickName,
                                userListDto.getNickName())
                        .like(StringUtils.isNotEmpty(userListDto.getUserName()), UserEntity::getUsername,
                                userListDto.getUserName());
        List<AccountVO> orgUsers = this.baseMapper.queryAccountVO((page.getCurrent() - 1) * page.getSize(), page.getSize(), queryWrapper);
        page.setTotal(this.baseMapper.selectCount(ObjectUtil.clone(queryWrapper)));
        page.setRecords(orgUsers);
        return page;
    }

    /**
     * 该组织是否存在用户
     * @param orgId 组织id
     * @return 布尔值
     */
    @Override
    public boolean isExistUserByOrgId(Long orgId){
        return Optional.ofNullable(this.baseMapper.getFirstUserIdByOrgId(orgId)).isPresent();
    }

    /**
     * 保存用户角色
     * @param roleIds 角色id列表
     * @param userId 用户id
     * @return 更改行数
     */
    @Override
    public int saveUserRoles(List<Long> roleIds, Long userId){
        roleIds = null==roleIds?new ArrayList<>():roleIds;
        QueryWrapper<UserRoleEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserRoleEntity::getUserId,userId);
        userRoleMapper.delete(queryWrapper);
        if(roleIds.size()==0){
            return 0;
        }
        List<UserRoleEntity> userRoleEntities = roleIds.stream()
                .map(m->
                        UserRoleEntity.builder()
                                .userId(userId)
                                .roleId(m)
                                .build()
                ).collect(Collectors.toList());
        return userRoleMapper.insertBatch(userRoleEntities);
    }

    /**
     * 添加用户
     *
     * @param userInsertParamDto 用户参数模型
     * @return 用户实体
     */
    public UserEntity insertUser(UserInsertParamDTO userInsertParamDto) {
        UserEntity existUser = getUserByUserName(userInsertParamDto.getUserName());
        if (null != existUser) {
            throw new BusinessException("重复的用户名！");
        }
        UserEntity userEntity = UserEntity.builder()
                .userName(userInsertParamDto.getUserName())
                .nickName(userInsertParamDto.getNickName())
                .password(BcryptEncoderUtil.encode(userInsertParamDto.getPassword()))
                .status(UserStatusEnum.NORMAL.getCode())
                .deleted(false)
                .build();
        this.save(userEntity);
        return userEntity;
    }

    /**
     * 给组织添加用户
     * 普通用户添加不需要组织参数，这个地方仅仅是给管理员服务的
     *
     * @param userInsertParamDto 组织对象
     */
    @Override
    public void insertAccount(UserInsertParamDTO userInsertParamDto) {
        // 密码解密
        String password = AesUtils.decrypt(userInsertParamDto.getPassword(), encryptKey);
        userInsertParamDto.setPassword(password);
        UserEntity user = insertUser(userInsertParamDto);
        if (userInsertParamDto.getUserOrg() != null) {
            saveUserOrg(userInsertParamDto.getUserOrg(),user.getId());
        }
    }

    /**
     * 更新账户
     *
     * @param userOrgUpdateParamDTO 修改参数对象
     * @param id                    对象id
     * @return 布尔值
     */
    @Override
    public boolean updateUser(UserOrgUpdateParamDTO userOrgUpdateParamDTO, Long id) {
        if (id == null) {
            return false;
        }
        LambdaUpdateWrapper<UserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(userOrgUpdateParamDTO.getNickName() != null, UserEntity::getNickName, userOrgUpdateParamDTO.getNickName())
                .eq(IdFieldEntity::getId, id);
        this.update(updateWrapper);
        if (userOrgUpdateParamDTO.getUserOrgRelations() != null) {
            saveUserOrg(userOrgUpdateParamDTO.getUserOrgRelations(), id);
        }
        return true;
    }

    private void saveUserOrg(List<UserOrgDTO> userOrgDtoList, Long userId) {
        LambdaQueryWrapper<UserOrgEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserOrgEntity::getUserId, userId);
        userOrgMapper.delete(queryWrapper);
        if (!userOrgDtoList.isEmpty()) {
            List<UserOrgEntity> userOrgEntities = userOrgDtoList.stream().map(userOrgDTO -> userOrgDTO.toUserOrgEntity(userId)).collect(Collectors.toList());
            orgService.saveBatch(userOrgEntities);
        }
    }

    /**
     * 通过用户名称获取实体
     * @param userName 用户名称
     * @return 用户实体
     */
    private UserEntity getUserByUserName(String userName) {
        return this.getOne(
                new LambdaQueryWrapper<UserEntity>()
                    .eq(UserEntity::getUsername, userName)
                    .eq(UserEntity::getDeleted,false)
        );
    }


    /**
     * 重置密码
     * @param userId 用户id
     * @return 新的密码
     */
    @Override
    public String resetPassword(Long userId){
        String newPassword = RandomStringUtils.randomAlphanumeric(6)+"_1Az";
        this.update(new LambdaUpdateWrapper<UserEntity>()
                .eq(UserEntity::getId,userId)
                .set(UserEntity::getPassword, BcryptEncoderUtil.encode(newPassword))
        );
        return AesUtils.encrypt(newPassword, encryptKey);
    }

    /**
     * 设置用户状态
     * @param status 状态值
     * @param userId 用户ID
     * @return 布尔值
     */
    @Override
    public Boolean setUserState(int status, Long userId){
        return this.update(
                new LambdaUpdateWrapper<UserEntity>()
                    .eq(UserEntity::getId,userId)
                        .set(UserEntity::getStatus,status)
        );
    }

    /**
     * 通过id列表找到对应的昵称
     * @param ids id集合
     * @return 包含nickname和id的对象集合
     */
    @Override
    public List<NickNameVo> listNickNamesByIds(List<Long> ids){
        return ids!=null&&!ids.isEmpty()?
                this.list(
                    new LambdaQueryWrapper<UserEntity>()
                        .in(IdFieldEntity::getId,ids)
                        .select(IdFieldEntity::getId,UserEntity::getNickName)
                ).stream()
                .map(NickNameVo::new)
                .collect(Collectors.toList()):
                new ArrayList<>();
    }

    /**
     * 删除用户
     * @param id 用户id
     * @return 更改行数
     */
    @Override
    public boolean deleteUserById(Long id) {
        LambdaUpdateWrapper<UserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(IdFieldEntity::getId, id).set(UserEntity::getDeleted, true);
        return this.update(updateWrapper);
    }

    /**
     * 通过用户名模糊查询用户列表
     * @param userName 用户名
     * @return 用户列表
     */
    @Override
    public List<UserEntity> listUserByUserName(String userName){
        return this.list(new LambdaQueryWrapper<UserEntity>().like(UserEntity::getUsername,userName));
    }


    /**
     * 判断该id是否是有效的用户
     * @param userId 用户id
     * @return 布尔值
     */
    @Override
    public boolean isExistUserById(Long userId){
        return this.getById(userId)!=null;
    }

    /**
     * 将用户移除组织
     * @param id 用户id
     * @param orgId 组织id
     * @return 布尔值
     */
    @Override
    public boolean removeFromOrg(Long id, Long orgId){
        LambdaQueryWrapper<UserOrgEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserOrgEntity::getUserId,id).eq(UserOrgEntity::getOrgId,orgId);
        return userOrgMapper.delete(queryWrapper) > 0;
    }

    @Override
    public List<SimpleUserVO> listUsersNotInOrg(Long orgId, String likeUserName){
        return this.baseMapper.listUsersNotInOrg(orgId,likeUserName);
    }


    @Override
    public void addOrgMember(MemberInsertParamDTO memberInsertParamDTO){
        if(null!=memberInsertParamDTO.getUserId()){
            LambdaQueryWrapper<UserOrgEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserOrgEntity::getUserId,memberInsertParamDTO.getUserId()).eq(UserOrgEntity::getOrgId,CurrentUserUtil.getCurrentUserOrgId());
            if(userOrgMapper.exists(queryWrapper)){
                log.warn("用户已存在该组织关联，可能是因为过滤非组织成员失败获取前端参数问题，该问题不影响当前系统，建议检查！");
            }else{
                UserOrgEntity userOrgEntity = UserOrgEntity.builder()
                        .orgId(CurrentUserUtil.getCurrentUserOrgId())
                        .userId(memberInsertParamDTO.getUserId())
                        .orgChief(false)
                        .build();
                userOrgMapper.insert(userOrgEntity);
            }
            saveUserRoles(memberInsertParamDTO.getRoleIds(),memberInsertParamDTO.getUserId());
        }
    }

}
